# 导入必要的库
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report
import plotly.graph_objects as go
from plotly.subplots import make_subplots

# 设置中文显示（确保中文正常显示）
plt.rcParams['font.sans-serif'] = ['SimHei']  # 使用 SimHei 字体支持中文
plt.rcParams['axes.unicode_minus'] = False  # 正常显示负号

# 1. 加载鸢尾花数据集
iris = load_iris()
X = iris.data  # 特征数据：花萼长度、花萼宽度、花瓣长度、花瓣宽度
y = iris.target  # 目标变量：0 (setosa), 1 (versicolor), 2 (virginica)

# 2. 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 3. 特征标准化
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# 4. 创建并训练多分类逻辑回归模型
model = LogisticRegression(multi_class='multinomial', solver='lbfgs', max_iter=200, random_state=42)
model.fit(X_train_scaled, y_train)

# 5. 预测
y_pred = model.predict(X_test_scaled)

# 6. 模型评估
accuracy = accuracy_score(y_test, y_pred)
conf_matrix = confusion_matrix(y_test, y_pred)
class_report = classification_report(y_test, y_pred, target_names=iris.target_names)

# 打印结果
print("多分类逻辑回归模型准确率:", accuracy)
print("\n混淆矩阵:\n", conf_matrix)
print("\n分类报告:\n", class_report)


# 7. 三维可视化决策边界和数据点
def plot_3d_decision_boundary(X, y, model, scaler):
    # 选择前三个特征：花萼长度、花萼宽度、花瓣长度
    X_3d = X[:, [0, 1, 2]]  # 花萼长度、花萼宽度、花瓣长度
    x_min, x_max = X_3d[:, 0].min() - 1, X_3d[:, 0].max() + 1
    y_min, y_max = X_3d[:, 1].min() - 1, X_3d[:, 1].max() + 1
    z_min, z_max = X_3d[:, 2].min() - 1, X_3d[:, 2].max() + 1

    # 创建网格
    xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.5),
                         np.arange(y_min, y_max, 0.5))
    z_grid = np.arange(z_min, z_max, 0.5)
    X_grid, Y_grid = np.meshgrid(np.arange(x_min, x_max, 0.5),
                                 np.arange(y_min, y_max, 0.5))
    Z_grid = np.zeros_like(X_grid)

    # 预测每个网格点的类别
    for i in range(X_grid.shape[0]):
        for j in range(X_grid.shape[1]):
            other_features = np.mean(X[:, 3:], axis=0)  # 花瓣宽度的均值
            grid_point = np.array([[X_grid[i, j], Y_grid[i, j], z] for z in z_grid])
            grid_point = np.c_[grid_point, np.full((len(z_grid), 1), other_features[0])]
            Z_grid[i, j] = model.predict(scaler.transform(grid_point))[0]

    # 创建三维子图
    fig = make_subplots(rows=1, cols=1, specs=[[{'type': 'surface'}]])

    # 添加决策边界表面
    fig.add_trace(go.Surface(x=xx, y=yy, z=Z_grid, colorscale='Viridis', opacity=0.5,
                             showscale=False, name='决策边界'))

    # 添加散点数据
    scatter = go.Scatter3d(x=X_3d[:, 0], y=X_3d[:, 1], z=X_3d[:, 2], mode='markers',
                           marker=dict(size=5, color=y, colorscale='Viridis', opacity=0.8),
                           text=[iris.target_names[i] for i in y], name='数据点')

    fig.add_trace(scatter)

    # 更新布局
    fig.update_layout(
        title='多分类逻辑回归三维决策边界',
        scene=dict(
            xaxis_title='花萼长度 (cm)',
            yaxis_title='花萼宽度 (cm)',
            zaxis_title='花瓣长度 (cm)',
            xaxis=dict(range=[x_min, x_max]),
            yaxis=dict(range=[y_min, y_max]),
            zaxis=dict(range=[z_min, z_max])
        ),
        width=800,
        height=800
    )

    fig.show()


# 调用函数绘制三维决策边界
plot_3d_decision_boundary(X, y, model, scaler)

# 8. 打印模型系数
print("\n多分类逻辑回归模型系数（每类一个系数向量）:")
for i, class_name in enumerate(iris.target_names):
    print(f"\n类别: {class_name}")
    print(pd.Series(model.coef_[i], index=iris.feature_names))
print("\n截距:", model.intercept_)